---
title: Data builders
---

<ExperimentalFeature>

**Data builders are currently [experimental](https://www.apollographql.com/docs/resources/product-launch-stages/#experimental-features) in Apollo Kotlin.** If you have feedback on them, please let us know via [GitHub issues](https://github.com/apollographql/apollo-kotlin/issues/new?assignees=&labels=Type%3A+Bug&template=bug_report.md) or in the [Kotlin Slack community](https://slack.kotl.in/).

</ExperimentalFeature>

Apollo Kotlin generates models for your operations and parsers that create instances of these models from your network responses. Sometimes though, during tests or in other occasions, it is useful to instantiate models manually with known values.

Doing so is not as straightforward as it may seem, especially when fragments are used. Creating `operationBased` models requires instantiating every fragment as well as choosing an appropriate `__typename` for each composite type.

Data builders make this easier by providing builders that match the structure of the Json document.

## Enabling data builders

To enable data builders, set the `generateDataBuilders` option to `true`:

```kotlin title="build.gradle[.kts]"
apollo {
  service("service") {
    // ...

    // Enable data builder generation
    generateDataBuilders.set(true)
  }
}
```

This generates a builder for each composite type in your schema as well as a helper `Data {}` function for each of your operations.

## Example usage

Let's say we're building a test that uses a mocked result of the following query:

```graphql
query HeroForEpisode($ep: Episode!) {
  hero(episode: $ep) {
    firstName
    lastName
    age
    
    ship {
      model
      speed
    }

    friends {
      firstName
      lastName
    }

    ... on Droid {
      primaryFunction
    }

    ... on Human {
      height
    }
  }
}
```

Here's how we can use the corresponding data builder for that mocked result:

```kotlin
@Test
fun test() {
  val data = HeroForEpisodeQuery.Data {
    // Set values for particular fields of the query
    hero = buildHuman {
      firstName = "John"
      age = 42
      friends = listOf(
        buildHuman {
          firstName = "Jane"
        }, 
        buildHuman {
          lastName = "Doe"
        }
      )
      ship = buildStarship {
        model = "X-Wing"
      }
    }
  }

  assertEquals("John", data.hero.firstName)
  assertEquals(42, data.hero.age)
}
```

In this example, the `hero` field is a `Human` object with specified values for `firstName` and `age`. The values for `lastName`and `height` are automatically populated with mock values.
Similarly, values for the ship's speed, the 1st friend's last name and 2nd friend's first name are automatically populated.

> You can replace `buildHuman` above with `buildDroid` to create a `Droid` object instead.

## Aliases 

Because data builders are schema-based and aliases are defined in your queries, there is no way for the codegen to generate builder fields for them. Instead, you'll need to specify them explicitly.

Given a query like this:

```graphql
query GetHeroes {
  luke: hero(id: "1002") {
    name
  }
  leia: hero(id: "1003") {
    name
  }
}
```

You can generate a fake data model like so:

```kotlin
val data = GetHeroes.Data {
  this["luke"] = buildHumanHero {
    name = "Luke"
  }
  this["leia"] = buildHumanHero {
    name = "Leia"
  }
}
```

## `@skip` and `@include` directives

By default, the data builders match the types in your schema. If a field is non-null you will either have to provide a value or let the default resolver provide one. This is an issue for `@skip` and `@include` directives where a field might be absent even if it is non-nullable. To account for this case, use the same syntax as for aliases and set the value to `Optional.Absent`.

```graphql
query Skip($skip: Boolean!) {
  nonNullableInt @skip(if: $skip)
}
```

You can generate a fake data model like so:

```kotlin
val data = SkipQuery.Data {
  this["nonNullableInt"] = Optional.Absent
}

assertNull(data.nonNullableInt) 
```

## Configuring default field values

To assign default values to fields, data builders use an implementation of the `FakeResolver` interface. By default, they use an instance of `DefaultFakeResolver`.

The `DefaultFakeResolver` gives each `String` field the field's name as its default value, and it increments a counter as it assigns default values for `Int` fields. It defines similar default behavior for other types.

You can create your _own_ `FakeResolver` implementation (optionally delegating to `DefaultFakeResolver` for a head start). You then pass this implementation as a parameter to the `Data` function, like so:

```kotlin {6}
// A FakeResolver implementation that assigns -1 to all Int fields
class MyFakeResolver : FakeResolver {
  private val delegate = DefaultFakeResolver(__Schema.all)
  
  override fun resolveLeaf(context: FakeResolverContext): Any {
    return when (context.mergedField.type.leafType().name) {
      "Int" -> -1 // Always use -1 for Int
      else -> delegate.resolveLeaf(context) 
    }
  }

  override fun resolveListSize(context: FakeResolverContext): Int {
    // Delegate to the default behaviour
    return delegate.resolveListSize(context)
  }

  override fun resolveMaybeNull(context: FakeResolverContext): Boolean {
    // Never 
    return false
  }

  override fun resolveTypename(context: FakeResolverContext): String {
    // Delegate to the default behaviour
    return delegate.resolveTypename(context)
  }
}

@Test
fun test() {
  val data = HeroForEpisodeQuery.Data(resolver = MyFakeResolver()) {
    hero = buildHuman {
      firstName = "John"
    }
  }

  // Unspecified Int field is -1
  assertEquals(-1, data.hero.age)
}
```

## Using fragments 

Because fragments may be defined on interfaces and unions, you need to explicit the concrete type you want to model. For an example, if you have an `Animal` interface, create a `Lion` fragment data using the following:

```kotlin
val data = AnimalDetailsImpl.Data(Lion) {
  // you can access roar here
  roar = "Grrrrr"
}
```

Sometimes, you may want to test new types defined in your server that are not known to the client yet. To do so, use the abstract type (`Animal` here) as first parameter for the `Data()` constructor function. 

In those cases, you need to specify the `__typename` of the returned object type explicitly: 

```kotlin
val data = AnimalDetailsImpl.Data(Animal) {
  // the client doesn't know about this type yet, and you need to specify it explicitly
  __typename = "Brontaroc"
  species = "alien"
}
```